window.addEventListener("DOMContentLoaded", function(indexUrl) {
  let index = null;
  let lookup = null;
  let queuedTerm = null;
  let queuedDoNotAddState = false;
  let origContent = null;

  const form = document.getElementById("search");
  const input = document.getElementById("search-input");

  form.addEventListener("submit", function(event) {
    event.preventDefault();

    let term = input.value.trim();
    if (!term) {
      return;
    }
    startSearch(term, false);
  }, false);

  if (history.state && history.state.type == "search") {
    startSearch(history.state.term, true);
  }

  window.addEventListener("popstate", function(event) {
    if (event.state && event.state.type == "search") {
      startSearch(event.state.term, true);
    }
    else if (origContent) {
      let target = document.querySelector(".container[role=main]");
      while (target.firstChild) {
        target.removeChild(target.firstChild);
      }

      for (let node of origContent) {
        target.appendChild(node);
      }
      origContent = null;
    }
  }, false);

  function startSearch(term, doNotAddState) {
    input.value = term;
    form.setAttribute("data-running", "true");
    if (index) {
      search(term, doNotAddState);
    }
    else if (queuedTerm) {
      queuedTerm = term;
      queuedDoNotAddState = doNotAddState;
    }
    else {
      queuedTerm = term;
      queuedDoNotAddState = doNotAddState;
      initIndex();
    }
  }

  function searchDone() {
    form.removeAttribute("data-running");

    queuedTerm = null;
    queuedDoNotAddState = false;
  }

  function initIndex() {
    let request = new XMLHttpRequest();
    request.open("GET", indexUrl);
    request.responseType = "json";
    request.addEventListener("load", function(event) {
      let documents = request.response;
      if (!documents)
      {
        console.error("Search index could not be downloaded.");
        searchDone();
        return;
      }

      lookup = {};
      index = lunr(function() {
        const language = document.documentElement.getAttribute("lang") || "en";
        if (language.length > 2)
          language = language.slice(0, 2);
        if (language != "en" && lunr.hasOwnProperty(language)) {
          this.use(lunr[language]);
        }

        this.ref("uri");
        this.field("title");
        this.field("subtitle");
        this.field("content");
        this.field("description");
        this.field("categories");
        this.field("tags");

        for (let document of documents) {
          this.add(document);
          lookup[document.uri] = document;
        }
      });

      search(queuedTerm, queuedDoNotAddState);
    }, false);
    request.addEventListener("error", searchDone, false);
    request.send(null);
  }

  function search(term, doNotAddState) {
    try {
      let results = index.search(term);

      let target = document.querySelector(".container[role=main]");
      let replaced = [];
      while (target.firstChild) {
        replaced.push(target.firstChild);
        target.removeChild(target.firstChild);
      }
      if (!origContent) {
        origContent = replaced;
      }

      let titleTemplate = document.getElementById("search-heading");
      let titleElement = titleTemplate.content.cloneNode(true);
      // This is an overly simple pluralization scheme, it will only work
      // for some languages.

      let title = titleElement.querySelector(".search-title");
      if (results.length == 0) {
        title.textContent = titleTemplate.getAttribute("data-results-none").replace("{}", term);
      }
      else if (results.length == 1) {
        title.textContent = titleTemplate.getAttribute("data-results-one").replace("{}", term);
      }
      else {
        title.textContent = titleTemplate.getAttribute("data-results-many").replace("{}", term).replace("13579", results.length);
      }
      target.appendChild(titleElement);
      document.title = title.textContent;

      let template = document.getElementById("search-result");
      for (let result of results) {
          let doc = lookup[result.ref];

          let element = template.content.cloneNode(true);
          element.querySelector(".summary-title-link").href = element.querySelector(".read-more-link").href = doc.uri;
          element.querySelector(".summary-title-link").textContent = doc.title;
          element.querySelector(".post-entry").textContent = truncateToEndOfSentence(doc.content, 70);
          target.appendChild(element);
      }
      title.scrollIntoView(true);

      if (!doNotAddState) {
          history.pushState({type: "search", term: term}, title.textContent, "#search=" + encodeURIComponent(term));
      }

      let menuToggler = document.querySelector(".navbar-toggler");
      if (menuToggler && !menuToggler.classList.contains("collapsed")) {
        menuToggler.click();
      }
    }
    finally {
      searchDone();
    }
  }

  // This matches Hugo's own summary logic:
  // https://github.com/gohugoio/hugo/blob/b5f39d23b86f9cb83c51da9fe4abb4c19c01c3b7/helpers/content.go#L543
  function truncateToEndOfSentence(text, minWords)
  {
      let match;
      let result = "";
      let wordCount = 0;
      let regexp = /(\S+)(\s*)/g;
      while (match = regexp.exec(text)) {
          wordCount++;
          if (wordCount <= minWords) {
              result += match[0];
          }
          else
          {
              let char1 = match[1][match[1].length - 1];
              let char2 = match[2][0];
              if (/[.?!"]/.test(char1) || char2 == "\n") {
                  result += match[1];
                  break;
              }
              else {
                  result += match[0];
              }
          }
      }
      return result;
  }
}.bind(null, document.currentScript.getAttribute("data-index")), {once: true});
